package com.ray.system.api;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ray.common.SysConstant;
import com.ray.common.SysMsgCodeConstant;
import com.ray.system.builder.CommonPageBuilder;
import com.ray.system.builder.MenuBuilder;
import com.ray.system.builder.MenuTreeBuilder;
import com.ray.system.check.AppCheck;
import com.ray.system.check.MenuCheck;
import com.ray.system.check.RoleCheck;
import com.ray.system.enums.MenuTypeEnum;
import com.ray.system.service.SysAppService;
import com.ray.system.service.SysMenuService;
import com.ray.system.service.SysRoleService;
import com.ray.system.service.SysUserMenuService;
import com.ray.system.service.compose.UserService;
import com.ray.system.table.TreeUtil;
import com.ray.system.table.dto.MenuQueryDTO;
import com.ray.system.table.entity.SysApp;
import com.ray.system.table.entity.SysMenu;
import com.ray.system.table.entity.SysRole;
import com.ray.system.table.params.CodeParams;
import com.ray.system.table.params.menu.MenuCreateParams;
import com.ray.system.table.params.menu.MenuEditParams;
import com.ray.system.table.params.menu.MenuQueryParams;
import com.ray.system.table.vo.menu.MenuTreeVO;
import com.ray.system.table.vo.menu.MenuVO;
import com.ray.validate.support.utils.ValidateUtil;
import com.ray.woodencreate.beans.CommonValue;
import com.ray.woodencreate.beans.LoginUser;
import com.ray.woodencreate.enums.YesOrNoEnum;
import com.ray.woodencreate.exception.BusinessExceptionFactory;
import com.ray.woodencreate.page.CommonPage;
import com.ray.woodencreate.result.MsgCodeConstant;
import com.ray.woodencreate.result.Result;
import com.ray.woodencreate.result.ResultFactory;
import com.ray.woodencreate.util.Assert;
import com.ray.woodencreate.util.LogInUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author bo shen
 * @Description: 菜单相关服务
 * @Class: MenuApi
 * @Package com.ray.system.api
 * @date 2020/5/27 11:15
 * @company <p>Ray快速开发平台</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Service
@Slf4j
public class MenuApi {

    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private SysAppService sysAppService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysUserMenuService sysUserMenuService;
    @Autowired
    private UserService userService;

    /**
     * 查询菜单列表信息 分页  非删除的
     *
     * @param queryParams
     * @return
     */
    public Result<IPage<MenuVO>> pageMenus(CommonPage<MenuQueryParams, Page<MenuVO>> queryParams) {
        Assert.notNull(queryParams, SysMsgCodeConstant.Error.ERR10000001);
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        CommonPageBuilder<MenuQueryDTO, SysMenu> commonPageBuilder = new CommonPageBuilder<>(MenuQueryDTO.class);
        commonPageBuilder.appendEntity(queryParams.getEntity()).appendCode(loginUser.getAppCode()).appendQuery(queryParams.getQuery()).appendPage(queryParams.getPage());
        IPage<SysMenu> page = sysMenuService.page(commonPageBuilder.bulid(), loginUser);
        List<SysMenu> Menus = page.getRecords();
        //结果对象
        IPage<MenuVO> pageList = new Page<>();
        pageList.setTotal(page.getTotal());
        pageList.setCurrent(page.getCurrent());
        pageList.setSize(page.getSize());
        //查询到结果 数据转换
        if (ObjectUtil.isNotNull(Menus)) {
            pageList.setRecords(Menus.stream().map(sysMenu -> {
                MenuVO MenuVO = new MenuVO();
                BeanUtil.copyProperties(sysMenu, MenuVO);
                return MenuVO;
            }).collect(Collectors.toList()));
        } else {
            pageList.setRecords(new ArrayList<>());
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, pageList);
    }

    /**
     * 查询菜单列表信息--启用的菜单
     *
     * @param queryParams
     * @return
     */
    public Result<List<MenuVO>> queryMenus(MenuQueryParams queryParams) {
        Assert.notNull(queryParams, SysMsgCodeConstant.Error.ERR10000001);
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        MenuQueryDTO queryDTO = new MenuQueryDTO();
        BeanUtil.copyProperties(queryParams, queryDTO);
        queryDTO.setStatus(YesOrNoEnum.YES.getValue());
        List<SysMenu> Menus = sysMenuService.list(queryDTO, loginUser);
        //查询对象
        List<MenuVO> list = new ArrayList<>();
        if (ObjectUtil.isNotNull(Menus)) {
            list = Menus.stream().map(sysMenu -> {
                MenuVO MenuVO = new MenuVO();
                BeanUtil.copyProperties(sysMenu, MenuVO);
                return MenuVO;
            }).collect(Collectors.toList());
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, list);
    }


    /**
     * 创建菜单
     *
     * @param createParams 创建对象
     * @return Result
     */
    @Transactional
    public Result<String> createMenu(MenuCreateParams createParams) {
        ValidateUtil.validate(createParams);
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        //判断上级菜单是否存在
        if (StrUtil.isNotBlank(createParams.getParentMenuCode()) && !StrUtil.equals(createParams.getParentMenuCode(), SysConstant.MENU_ROOT)) {
            SysMenu parentMenu = sysMenuService.queryMenuByMenuCode(createParams.getParentMenuCode(), loginUser);
            new MenuCheck(parentMenu).checkNull(SysMsgCodeConstant.Error.ERR10000006)
                    .chechSamAppCode(createParams.getAppCode(), SysMsgCodeConstant.Error.ERR10000008)
                    .checkType(createParams.getMenuType(), SysMsgCodeConstant.Error.ERR10000008);
        } else {
            //第一级 只能是菜单
            createParams.setMenuType(MenuTypeEnum.MENU.getValue());
        }

        //判断APP是否存在
        SysApp sysApp = sysAppService.queryAppByAppCode(createParams.getAppCode(), loginUser);
        new AppCheck(sysApp).checkNull(SysMsgCodeConstant.Error.ERR10000002);
        MenuBuilder MenuBuilder = new MenuBuilder();
        MenuBuilder.append(createParams).appendStatus(YesOrNoEnum.YES.getValue()).appendCreate(loginUser);
        //保存菜单信息
        if (!sysMenuService.save(MenuBuilder.bulid())) {
            log.info("保存菜单接口异常,参数:{}", JSON.toJSONString(MenuBuilder.bulid()));
            throw BusinessExceptionFactory.newException(MsgCodeConstant.Error.ERR00000001);
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001, MenuBuilder.getCode());
    }

    /**
     * 编辑菜单
     *
     * @param editParams 编辑对象
     * @return Result
     */
    @Transactional
    public Result<String> editMenu(MenuEditParams editParams) {
        ValidateUtil.validate(editParams);
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        //判断上级菜单是否存在
        if (StrUtil.isNotBlank(editParams.getParentMenuCode()) && !StrUtil.equals(editParams.getParentMenuCode(), SysConstant.MENU_ROOT)) {
            SysMenu parentMenu = sysMenuService.queryMenuByMenuCode(editParams.getParentMenuCode(), loginUser);
            new MenuCheck(parentMenu).checkNull(SysMsgCodeConstant.Error.ERR10000006).chechSamAppCode(editParams.getAppCode(), SysMsgCodeConstant.Error.ERR10000008);
        }
        //判断APP是否存在
        SysApp sysApp = sysAppService.queryAppByAppCode(editParams.getAppCode(), loginUser);
        new AppCheck(sysApp).checkNull(SysMsgCodeConstant.Error.ERR10000002);
        MenuBuilder MenuBuilder = new MenuBuilder();
        MenuBuilder.append(editParams).appendEdit(loginUser);
        //编辑菜单信息
        if (!sysMenuService.edit(MenuBuilder.bulid(), loginUser)) {
            log.info("编辑菜单接口异常,参数:{}", JSON.toJSONString(MenuBuilder.bulid()));
            throw BusinessExceptionFactory.newException(MsgCodeConstant.Error.ERR00000001);
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001, MenuBuilder.getCode());
    }


    /**
     * 删除菜单
     *
     * @param menuCode 菜单编码
     * @return Result
     */
    @Transactional
    public Result<String> deleteMenu(String menuCode) {
        ValidateUtil.hasLength(menuCode, "参数[MenuCode]不能为空");
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        //判断是否有子部门
        Integer childMenuCount = sysMenuService.countChildMenu(menuCode);
        //获取权限信息
        SysMenu sysMenu = sysMenuService.queryMenuByMenuCode(menuCode, loginUser);
        new MenuCheck(sysMenu).checkNull(SysMsgCodeConstant.Error.ERR10000002).checkNotHasChild(childMenuCount, SysMsgCodeConstant.Error.ERR10000005);
        MenuBuilder MenuBuilder = new MenuBuilder();
        MenuBuilder.appendCode(menuCode).appendEdit(loginUser).delete();
        //删除菜单信息
        if (!sysMenuService.edit(MenuBuilder.bulid(), loginUser)) {
            log.info("删除菜单接口异常,参数:{}", JSON.toJSONString(MenuBuilder.bulid()));
            throw BusinessExceptionFactory.newException(MsgCodeConstant.Error.ERR00000001);
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001, MenuBuilder.getCode());
    }

    /**
     * 开启菜单
     *
     * @param menuCode 菜单编码
     * @return Result
     */
    @Transactional
    public Result<String> openMenu(String menuCode) {
        ValidateUtil.hasLength(menuCode, "参数[MenuCode]不能为空");
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        //获取权限信息
        SysMenu sysMenu = sysMenuService.queryMenuByMenuCode(menuCode, loginUser);
        new MenuCheck(sysMenu).checkNull(SysMsgCodeConstant.Error.ERR10000002);
        MenuBuilder MenuBuilder = new MenuBuilder();
        MenuBuilder.appendCode(menuCode).appendEdit(loginUser).open();
        //开启菜单信息
        if (!sysMenuService.edit(MenuBuilder.bulid(), loginUser)) {
            log.info("开启菜单接口异常,参数:{}", JSON.toJSONString(MenuBuilder.bulid()));
            throw BusinessExceptionFactory.newException(MsgCodeConstant.Error.ERR00000001);
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001, MenuBuilder.getCode());
    }

    /**
     * 开启菜单
     *
     * @param MenuCode 菜单编码
     * @return Result
     */
    @Transactional
    public Result<String> closeMenu(String MenuCode) {
        ValidateUtil.hasLength(MenuCode, "参数[MenuCode]不能为空");
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        //获取权限信息
        SysMenu sysMenu = sysMenuService.queryMenuByMenuCode(MenuCode, loginUser);
        new MenuCheck(sysMenu).checkNull(SysMsgCodeConstant.Error.ERR10000002);
        MenuBuilder MenuBuilder = new MenuBuilder();
        MenuBuilder.appendCode(MenuCode).appendEdit(loginUser).close();
        //关闭菜单信息
        if (!sysMenuService.edit(MenuBuilder.bulid(), loginUser)) {
            log.info("关闭菜单接口异常,参数:{}", JSON.toJSONString(MenuBuilder.bulid()));
            throw BusinessExceptionFactory.newException(MsgCodeConstant.Error.ERR00000001);
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001, MenuBuilder.getCode());
    }

    /**
     * 菜单详情
     *
     * @param menuCode 菜单编码
     * @return Result
     */
    public Result<MenuVO> viewMenu(String menuCode) {
        ValidateUtil.hasLength(menuCode, "参数[MenuCode]不能为空");
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        //获取权限信息
        SysMenu sysMenu = sysMenuService.queryMenuByMenuCode(menuCode, loginUser);
        new MenuCheck(sysMenu).checkNull(SysMsgCodeConstant.Error.ERR10000002);
        MenuVO menuVO = new MenuVO();
        BeanUtil.copyProperties(sysMenu, menuVO);
        SysMenu parentMenu = sysMenuService.queryMenuByMenuCode(sysMenu.getParentMenuCode(), loginUser);
        if (ObjectUtil.isNotNull(parentMenu)) {
            menuVO.setParentMenuName(parentMenu.getMenuName());
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, menuVO);
    }

    /**
     * 树形列表
     *
     * @param queryParams
     * @return
     */
    public Result<List<MenuTreeVO>> tree(@Valid CodeParams queryParams) {
        LoginUser loginUser = LogInUserUtil.get();
        //获取系统信息
        SysApp sysApp = sysAppService.queryAppByAppCode(queryParams.getCode());
        new AppCheck(sysApp).checkNull(SysMsgCodeConstant.Error.ERR10000013);
        //菜单权限
        MenuQueryDTO queryDTO = new MenuQueryDTO();
        queryDTO.setAppCode(queryParams.getCode());
        List<SysMenu> sysMenus = sysMenuService.list(queryDTO, loginUser);
        List<MenuTreeVO> menuTreeList = sysMenus.stream().map(sysMenu -> {
            return new MenuTreeBuilder().append(sysMenu).bulid();
        }).sorted(Comparator.comparingInt(menu -> {
            return ObjectUtil.isNotNull(menu.getIndexSort()) ? menu.getIndexSort() : 0;
        })).collect(Collectors.toList());
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, TreeUtil.bulid(menuTreeList, SysConstant.MENU_ROOT));
    }

    /**
     * 树形列表
     *
     * @param queryParams
     * @return
     */
    public Result<List<MenuTreeVO>> authTree(@Valid CodeParams queryParams) {
        LoginUser loginUser = LogInUserUtil.get();
        //角色判断
        SysRole sysRole = sysRoleService.queryRoleByRoleCode(queryParams.getCode(), loginUser);
        new RoleCheck(sysRole).checkNull(SysMsgCodeConstant.Error.ERR10000002);
        //查询当前用户拥有的菜单
        List<SysMenu> sysMenus = userService.queryMenus(sysRole.getAppCode(), loginUser);
        //查询角色下所有菜单
        List<String> menuCodes = sysUserMenuService.queryMenuByRoleCode(queryParams.getCode()).stream().map(sysUserMenu -> {
            return sysUserMenu.getMenuCode();
        }).collect(Collectors.toList());
        List<MenuTreeVO> menuTreeList = sysMenus.stream().map(sysMenu -> {
            return new MenuTreeBuilder().append(sysMenu).appendAuth(menuCodes.contains(sysMenu.getMenuCode())).bulid();
        }).sorted(Comparator.comparingInt(menu -> {
            return ObjectUtil.isNotNull(menu.getIndexSort()) ? menu.getIndexSort() : 0;
        })).collect(Collectors.toList());
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, TreeUtil.bulid(menuTreeList, SysConstant.MENU_ROOT));
    }

    /**
     * 创建默认按钮
     *
     * @param menuCode
     * @return
     */
    public Result<String> createBtn(String menuCode) {
        LoginUser loginUser = LogInUserUtil.get();
        //获取权限信息
        SysMenu sysMenu = sysMenuService.queryMenuByMenuCode(menuCode, loginUser);
        new MenuCheck(sysMenu).checkNull(SysMsgCodeConstant.Error.ERR10000002).checkType(MenuTypeEnum.BTN.getValue(), SysMsgCodeConstant.Error.ERR10000008);
        //查询是否已经有子节点

        Integer count = sysMenuService.countChildMenu(menuCode);
        if (count == 0) {
            List<SysMenu> sysMenus = new ArrayList<>();
            sysMenus.add(new MenuBuilder().appendName("新增")
                    .appendParentMenuCode(sysMenu.getMenuCode()).appendPermission("_add")
                    .appendAppCode(sysMenu.getAppCode()).appendCreate(loginUser).bulid());
            sysMenus.add(new MenuBuilder().appendName("编辑")
                    .appendParentMenuCode(sysMenu.getMenuCode()).appendPermission("_edit")
                    .appendAppCode(sysMenu.getAppCode()).appendCreate(loginUser).bulid());
            sysMenus.add(new MenuBuilder().appendName("查看")
                    .appendParentMenuCode(sysMenu.getMenuCode()).appendPermission("_view")
                    .appendAppCode(sysMenu.getAppCode()).appendCreate(loginUser).bulid());
            sysMenus.add(new MenuBuilder().appendName("删除")
                    .appendParentMenuCode(sysMenu.getMenuCode()).appendPermission("_delete")
                    .appendAppCode(sysMenu.getAppCode()).appendCreate(loginUser).bulid());
            sysMenus.add(new MenuBuilder().appendName("开启")
                    .appendParentMenuCode(sysMenu.getMenuCode()).appendPermission("_open")
                    .appendAppCode(sysMenu.getAppCode()).appendCreate(loginUser).bulid());
            sysMenus.add(new MenuBuilder().appendName("关闭")
                    .appendParentMenuCode(sysMenu.getMenuCode()).appendPermission("_close")
                    .appendAppCode(sysMenu.getAppCode()).appendCreate(loginUser).bulid());
            sysMenuService.saveBatch(sysMenus);
        }


        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001, menuCode);

    }
}
